From Nand to Tetris week 5
这次回顾第五章的内容,这一章介绍了计算机体系结构,完整搭建了一个计算机。
课程官网:
视频地址:
https://www.coursera.org/learn/build-a-computer
Chapter 5 计算机体系结构
Part 1:课程回顾
这部分内容从略,这一章的主要内容为项目部分。
Part 2:项目
Memory
Memory的架构如下:
关键问题是判断address和16383以及24576的关系,注意到上述数字的二进制表示为:
所以可以根据address[14]和address[13]判断操作的位置,对应代码如下:
//判断是否小于16384, 利用address的最高位判断
DMux(in=load, sel=address[14], a=ram, b=device);
RAM16K(in=in, load=ram, address=address[0..13], out=out1);
//判断是否等于24576,利用address的倒数第二位判断
DMux(in=device, sel=address[13], a=screen, b=keyboard);
Screen(in=in, load=screen, address=address[0..12], out=d1);
Keyboard(out=d2);
//汇总
Mux16(a=d1, b=d2, sel=address[13], out=out2);
Mux16(a=out1, b=out2, sel=address[14], out=out);
CPU
CPU的架构如下:
instruction为16位二进制数,格式为
其中$i$表示指令类型,$0$表示A指令,$1$表示C指令。如果是C指令,a位域和c位域共同表示comp部分,指明进行什么计算,d位域表示dest部分,j位域表示jump部分;如果是A指令,那么除了i位之外的15位被解释为常数。
A指令的形式如下:
C指令的形式如下:
ARegister
首先考虑A寄存器,注意只有A指令才会对A寄存器操作,所以instruction相连的Mux16根据$i$进行判断:
//判断是否为A指令ALUout,根据最左边一位判断
Mux16(a=instruction, b=ALUout, sel=instruction[15], out=Ain);
另外这里要考虑d位域,实际上有如下关系:
不难看出只有d1为1的时候数据才会存储到A寄存器(注意此时指令为C指令,即第一位为0),因此这部分代码如下:
//计算loadA, instruction[15]=0时才需考虑instruction[5]
Not(in=instruction[15], out=a);
Or(a=a, b=instruction[5], out=loadA);
//A寄存器
ARegister(in=Ain, load=loadA, out=Aout, out[0..14]=addressM);
DRegister
接着考虑D寄存器,注意只有C指令才会对A寄存器操作,结合上图可得只有d2为1的时候数据才会存储到D寄存器,因此这部分代码如下:
//计算loadD
And(a=instruction[15], b=instruction[4], out=loadD);
//D寄存器
DRegister(in=ALUout, load=loadD, out=Dout);
注意DRegister的输出为ALU一个输入。
ALU
这部分讨论ALU,首先考虑ALU的另一个输入,这部分和inM以及ARegister的输出有关,控制位由a决定:
对应代码如下:
//ALU的另一个输入
Mux16(a=Aout, b=inM, sel=instruction[12], out=ALUin);
ALU部分的代码如下:
//ALU
ALU(x=Dout, y=ALUin, zx=instruction[11], nx=instruction[10], zy=instruction[9], ny=instruction[8], f=instruction[7], no=instruction[6],
out=ALUout, out=outM, zr=zr, ng=ng);
writeM
依旧回顾下图:
注意只有C指令以及d3=1时,才会输出到RAM[A],所以这部分的代码如下:
//writeM,只有为C指令的时候writeM才有效
And(a=instruction[3], b=instruction[15], out=writeM);
pc
这部分讨论pc,我们希望实现的功能如下:
现有元件为:
对比后不难发现inc应该恒取true,关键点是决定load,实际上有下图:
首先计算j1,j2,j3:
//load,只有C指令才考虑PC
And(a=instruction[15], b=instruction[2], out=j1);
And(a=instruction[15], b=instruction[1], out=j2);
And(a=instruction[15], b=instruction[0], out=j3);
out为ALU输出的正负,根据此图,首先需要构造判断out>0的布尔逻辑:
//判断out正负
Not(in=zr, out=notzr);
Not(in=ng, out=notng);
And(a=notzr, b=notng, out=pos);
接着根据out的正负号进行匹配即可,结合上图不难得到pc的构造方式:
//匹配j1,j2,j3
And(a=j1, b=ng, out=l1);
And(a=j2, b=zr, out=l2);
And(a=j3, b=pos, out=l3);
//输出load
Or(a=l1, b=l2, out=o1);
Or(a=o1, b=l3, out=load);
//PC,inc恒为true
PC(in=Aout, reset=reset, load=load, inc=true, out[0..14]=pc);
Computer
这部分根据下图的架构构造即可:
对应代码如下:
CPU(inM=inM, instruction=instruction, reset=reset,
writeM=writeM, outM=outM, addressM=addressM, pc=pc);
Memory(in=outM, load=writeM, address=addressM, out=inM);
ROM32K(address=pc, out=instruction);